<template>
  <view
    v-bind="$attrs"
    :class="['ea-gesture', getHoldAnimation ? 'ea-gesture-holding' : '']"
    @touchstart.stop.prevent="handleTouchStart"
    @touchmove.stop.prevent="handleTouchMove"
    @touchend.stop.prevent="handleTouchEnd"
    @touchcancel.stop.prevent="handleTouchEnd"
  >
    <slot></slot>
  </view>
</template>

<script lang="ts" setup>
  import { ref } from 'vue';

  import { useTouch } from '@/hooks/useTouch';

  import { gestureProps } from './props';

  defineOptions({
    name: 'ea-gesture',
    options: {
      virtualHost: true,
      addGlobalClass: true,
      styleIsolation: 'shared',
    },
  });
  const props = defineProps(gestureProps);
  const emit = defineEmits([
    'hold', // 长按事件
    'click', // 单击事件
    'doubleClick', // 双击事件
    'swipe', // 滑动事件
    'swipeUp', // 向上滑动事件
    'swipeDown', // 向下滑动事件
    'swipeLeft', // 向左滑动事件
    'swipeRight', // 向右滑动事件
  ]);

  const touch = useTouch();

  /** 长按中 */
  const holding = defineModel<boolean>('holding', { default: false });
  /** 手指停留时间(ms) */
  const stayTime = ref(0);
  /** 单击时间(ms) */
  const clickTime = ref(0);
  /** 长按计时器 */
  const holdTimer = ref<IntervalHandle | null>(null);
  /** 点击计时器 */
  const clickTimer = ref<IntervalHandle | null>(null);

  /** 获取是否开启长按动画 */
  const getHoldAnimation = computed(() => {
    const { holdAni } = props;
    if (holdAni === false) {
      return holdAni;
    }
    return holding.value;
  });

  /** 当用户的手指触摸屏幕时触发 */
  const handleTouchStart = (event: TouchEvent) => {
    const { stayDuration, holdVibrate } = props;
    touch.touchStart(event);

    holding.value = true;
    // 开始计时
    holdTimer.value = setInterval(() => {
      stayTime.value += 10;
      if (stayTime.value > stayDuration) {
        // 长按事件
        if (holding.value) {
          // 震动反馈
          if (holdVibrate) {
            uni.vibrateShort();
          }
          emit('hold', { ...event, type: 'hold' });
        }
        // reset();
        holding.value = false;
        stayTime.value = 0;
      }
    }, 10);
  };

  /** 当手指在屏幕上滑动时连续触发 */
  const handleTouchMove = (event: TouchEvent) => {
    touch.touchMove(event);
  };

  /** 当手指离开屏幕时触发 */
  const handleTouchEnd = (event: TouchEvent) => {
    // 非长按模式下，判断其他手势。
    if (holding.value) {
      const { direction, arrow } = touch;
      if (direction.value !== '' && arrow.value !== '') {
        // 滑动手势判断
        emit('swipe', { ...event, type: 'swipe', direction: direction.value, arrow: arrow.value });
      } else {
        // 单击/双击手势判断
        const currentTime = event.timeStamp;
        const lastClickTime = clickTime.value;
        clickTime.value = currentTime;
        const { clickInterval } = props;
        if (currentTime - lastClickTime < clickInterval) {
          emit('doubleClick', { ...event, type: 'doubleClick' });
          // 清除计时器
          clickTime.value = 0;
          if (clickTimer.value) {
            clearTimeout(clickTimer.value);
          }
        } else {
          clickTimer.value = setTimeout(() => {
            emit('click', { ...event, type: 'click' });
            // 清除计时器
            if (clickTimer.value) {
              clearTimeout(clickTimer.value);
            }
          }, clickInterval);
        }
      }
    }
    reset();
  };

  /** 重置状态 */
  function reset() {
    holding.value = false;
    stayTime.value = 0;
    // clickTime.value = 0;
    // 停止计时
    if (holdTimer.value) {
      clearInterval(holdTimer.value);
    }
    // if (clickTimer.value) {
    //   clearTimeout(clickTimer.value);
    // }
  }
</script>

<style lang="scss" scoped>
  @import './index';
</style>
